import { Like } from 'typeorm';
import { FindOptionsWhere } from 'typeorm/find-options/FindOptionsWhere';
import { PageQuery } from './entity/page.entity';
import { ValueTransformer } from 'typeorm/decorator/options/ValueTransformer';
import { readdir, stat } from 'fs/promises';
import { resolve, join } from 'path';
export type Obj = Record<string, any>;

// 为查询构建where
export function buildWhere<T extends Obj>(
  query: T,
  extraWhere?: FindOptionsWhere<T>,
): FindOptionsWhere<T> {
  let where: FindOptionsWhere<T> = {};
  if (extraWhere) {
    where = { ...extraWhere };
  }
  for (const key in query) {
    const value = query[key];
    if (value || Object.is(value, 0) || Object.is(value, false)) {
      if (['number', 'boolean', 'object'].includes(typeof value)) {
        where[key] = value;
      } else if (typeof value === 'string') {
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        where[key] = Like(`%${value}%`);
      }
    }
  }
  return where;
}

/**
 * 强大的查询构建
 * @param pageQuery
 * @param extraWhere
 */
export function buildQuery<T>(
  pageQuery: PageQuery<T>,
  extraWhere?: FindOptionsWhere<T>,
) {
  const { pageSize, currentPage, query } = pageQuery;
  const where = buildWhere(query, extraWhere);
  const order = pageQuery.order ?? {};
  const relations = pageQuery.relations ?? {};
  const skip = (currentPage - 1) * pageSize;
  const take = pageSize;
  const cache = pageQuery.cache ?? true;
  return { where, order, skip, take, cache, relations };
}

/**
 * 睡觉函数
 * @param timeout
 * @param random
 */
export function sleep(timeout = 1000, random = false) {
  return new Promise((resolve) => {
    if (random) {
      timeout = Math.floor(Math.random() * timeout);
    }
    setTimeout(resolve, timeout);
  });
}

/**
 * 检查一个值是否有效,仅仅用于query的时候
 * @param value
 */
export function isValueValid(value: any) {
  if (['string'].includes(typeof value)) {
    return !!value;
  } else if (
    ['number', 'boolean', 'bigint', 'symbol', 'function'].includes(typeof value)
  ) {
    // 数字,布尔统一放行
    return true;
  } else if (['undefined'].includes(typeof value) || value === null) {
    // undefined和null统一无效
    return false;
  } else {
    // 剩下数组和obj,直接为true
    return true;
  }
}

/**
 * 检查一个对象的属性是否有效
 * 前提:只检查基础类型
 */
export function isObjValid(obj: Obj): boolean {
  for (const objKey in obj) {
    const value = obj[objKey];
    // 只要其中有一个有效,就表示是一个有效的对象
    if (isValueValid(value)) {
      return true;
    }
  }
  return false;
}

/**
 * 转换bigInt
 */
export class TransformBigint implements ValueTransformer {
  // 写入数据库
  to(value: number) {
    return value;
  }
  // 从数据库读取
  from(value: string) {
    return parseInt(value);
  }
}

/**
 * 处理得到图片路径的时候,写入完整路径
//  */
// export class TransformImageUrl implements ValueTransformer{
//   from(value: string): string {
//     return value
//   }
//
//   to(value: any): any {
//   }
//
// }

/**
 * 获取[min,max]之间的随机数
 * @param min
 * @param max
 */
export function getRandomFrom(min = 1, max = 100) {
  const choices = max - min + 1;
  return Math.floor(Math.random() * choices + min);
}

/**
 * 处理异常 let [err,res] = await handleError(asyncFunc)
 * @param asyncFunc
 * @return {Promise<*[]>}
 */
export async function handleError<T = any>(
  asyncFunc: () => Promise<T>,
): Promise<[null, T] | [Error, null]> {
  try {
    const res = await asyncFunc();
    return [null, res];
  } catch (e: any) {
    return [e, null];
  }
}

//要遍历的文件夹所在的路径
const defaultPath = resolve('public/images');

/**
 * 文件遍历方法
 * @param filePath 需要遍历的文件路径
 * @param dirName  文件夹名称
 */
export async function getFilesByPath(
  filePath: string = defaultPath,
  dirName = '',
) {
  const arrPath: string[] = [];
  //根据文件路径读取文件，返回文件列表
  const [err, files] = await handleError(() => readdir(filePath));
  if (err) {
    console.error('读取文件夹失败:', err.message);
  }
  if (files && files.length > 0) {
    // 如果有结果的话
    for (const fileName of files) {
      // fileName是文件名称 比如 aaa.txt  或是文件夹比如:test
      const innerFilePath = join(filePath, fileName); // 拼接后的文件完整路径
      // 确定这个路径的状态
      const fileStat = await stat(innerFilePath);
      if (fileStat.isFile()) {
        // 如果是文件
        const finalName = join(dirName, fileName);
        arrPath.push(finalName);
      } else if (fileStat.isDirectory()) {
        // 如果是文件夹
        dirName = join(dirName, fileName);
        const result = await getFilesByPath(innerFilePath, dirName);
        arrPath.push(...result); //递归，如果是文件夹，就继续遍历该文件夹下面的文件
      }
    }
  }
  return arrPath;
}
